<!-- HTML header for doxygen 1.8.20-->
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
	<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
	<meta http-equiv="X-UA-Compatible" content="IE=9"/>
	<meta name="generator" content="Doxygen 1.9.4"/>
	<meta name="viewport" content="width=device-width, initial-scale=1"/>
	<title>Raspberry Pi Pico SDK: hardware_xip_cache</title>
	<!-- <link href="tabs.css" rel="stylesheet" type="text/css"/> -->
	<script type="text/javascript" src="jquery.js"></script>
	<script type="text/javascript" src="dynsections.js"></script>
	<link href="navtree.css" rel="stylesheet" type="text/css"/>
<script type="text/javascript" src="resize.js"></script>
<script type="text/javascript" src="navtreedata.js"></script>
<script type="text/javascript" src="navtree.js"></script>
	<link href="search/search.css" rel="stylesheet" type="text/css"/>
<script type="text/javascript" src="search/searchdata.js"></script>
<script type="text/javascript" src="search/search.js"></script>
    <link href="https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500&display=swap" rel="stylesheet">
	<link href="doxygen.css" rel="stylesheet" type="text/css" />
	<link href="normalise.css" rel="stylesheet" type="text/css"/>
<link href="main.css" rel="stylesheet" type="text/css"/>
<link href="styles.css" rel="stylesheet" type="text/css"/>
</head>
<body>
	<div class="navigation-mobile">
		<div class="logo--mobile">
			<a href="/"><img src="logo-mobile.svg" alt="Raspberry Pi"></a>
		</div>
		<div class="navigation-toggle">
			<span class="line-1"></span>
			<span class="line-2">
				<p>Menu Toggle</p>
			</span>
			<span class="line-3"></span>
		</div>
	</div>
	<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
		<div class="logo">
			<a href="index.html"> <img src="logo.svg" alt="Raspberry Pi"></a>
			<span style="display: inline-block; margin-top: 10px;">
				v2.1.0
			</span>
		</div>
		<div class="navigation-footer">
			<img src="logo-mobile.svg" alt="Raspberry Pi">
			<a href="https://www.raspberrypi.com/" target="_blank">By Raspberry Pi Ltd</a>
		</div>
<!-- 		<div class="search">
			<form>
				<input type="search" name="search" id="search" placeholder="Search">
				<input type="submit" value="Search">
			</form>
		</div> -->
<!-- Generated by Doxygen 1.9.4 -->
<script type="text/javascript">
/* @license magnet:?xt=urn:btih:d3d9a9a6595521f9666a5e94cc830dab83b65699&amp;dn=expat.txt MIT */
var searchBox = new SearchBox("searchBox", "search",'Search','.html');
/* @license-end */
</script>
<script type="text/javascript" src="menudata.js"></script>
<script type="text/javascript" src="menu.js"></script>
<script type="text/javascript">
/* @license magnet:?xt=urn:btih:d3d9a9a6595521f9666a5e94cc830dab83b65699&amp;dn=expat.txt MIT */
$(function() {
  initMenu('',true,false,'search.php','Search');
  $(document).ready(function() { init_search(); });
});
/* @license-end */
</script>
<div id="main-nav"></div>
</div><!-- top -->
<div id="side-nav" class="ui-resizable side-nav-resizable">
  <div id="nav-tree">
    <div id="nav-tree-contents">
      <div id="nav-sync" class="sync"></div>
    </div>
  </div>
  <div id="splitbar" style="-moz-user-select:none;" 
       class="ui-resizable-handle">
  </div>
</div>
<script type="text/javascript">
/* @license magnet:?xt=urn:btih:d3d9a9a6595521f9666a5e94cc830dab83b65699&amp;dn=expat.txt MIT */
$(document).ready(function(){initNavTree('group__hardware__xip__cache.html',''); initResizable(); });
/* @license-end */
</script>
<div id="doc-content">
<!-- window showing the filter options -->
<div id="MSearchSelectWindow"
     onmouseover="return searchBox.OnSearchSelectShow()"
     onmouseout="return searchBox.OnSearchSelectHide()"
     onkeydown="return searchBox.OnSearchSelectKey(event)">
</div>

<!-- iframe showing the search results (closed by default) -->
<div id="MSearchResultsWindow">
<iframe src="javascript:void(0)" frameborder="0" 
        name="MSearchResults" id="MSearchResults">
</iframe>
</div>

<div class="header">
  <div class="summary">
<a href="#func-members">Functions</a>  </div>
  <div class="headertitle"><div class="title">hardware_xip_cache<div class="ingroups"><a class="el" href="group__hardware.html">Hardware APIs</a></div></div></div>
</div><!--header-->
<div class="contents">

<p>Low-level cache maintenance operations for the XIP cache.  
<a href="#details">More...</a></p>
<table class="memberdecls">
<tr class="heading"><td colspan="2"><h2 class="groupheader"><a id="func-members" name="func-members"></a>
Functions</h2></td></tr>
<tr class="memitem:ga080199b0a555c0f19ff05a298fa97676"><td class="memItemLeft" align="right" valign="top">void&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="group__hardware__xip__cache.html#ga080199b0a555c0f19ff05a298fa97676">xip_cache_invalidate_all</a> (void)</td></tr>
<tr class="memdesc:ga080199b0a555c0f19ff05a298fa97676"><td class="mdescLeft">&#160;</td><td class="mdescRight">Invalidate the cache for the entire XIP address space.  <a href="group__hardware__xip__cache.html#ga080199b0a555c0f19ff05a298fa97676">More...</a><br /></td></tr>
<tr class="separator:ga080199b0a555c0f19ff05a298fa97676"><td class="memSeparator" colspan="2">&#160;</td></tr>
<tr class="memitem:ga1594edcbd2868564b190f3374d3f49eb"><td class="memItemLeft" align="right" valign="top">void&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="group__hardware__xip__cache.html#ga1594edcbd2868564b190f3374d3f49eb">xip_cache_invalidate_range</a> (uintptr_t start_offset, uintptr_t size_bytes)</td></tr>
<tr class="memdesc:ga1594edcbd2868564b190f3374d3f49eb"><td class="mdescLeft">&#160;</td><td class="mdescRight">Invalidate a range of offsets within the XIP address space.  <a href="group__hardware__xip__cache.html#ga1594edcbd2868564b190f3374d3f49eb">More...</a><br /></td></tr>
<tr class="separator:ga1594edcbd2868564b190f3374d3f49eb"><td class="memSeparator" colspan="2">&#160;</td></tr>
<tr class="memitem:gab7db8e534f4d6ff4a5fb7b022c3034a4"><td class="memItemLeft" align="right" valign="top">void&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="group__hardware__xip__cache.html#gab7db8e534f4d6ff4a5fb7b022c3034a4">xip_cache_clean_all</a> (void)</td></tr>
<tr class="memdesc:gab7db8e534f4d6ff4a5fb7b022c3034a4"><td class="mdescLeft">&#160;</td><td class="mdescRight">Clean the cache for the entire XIP address space.  <a href="group__hardware__xip__cache.html#gab7db8e534f4d6ff4a5fb7b022c3034a4">More...</a><br /></td></tr>
<tr class="separator:gab7db8e534f4d6ff4a5fb7b022c3034a4"><td class="memSeparator" colspan="2">&#160;</td></tr>
<tr class="memitem:ga2d424f9667df473c64d6414f31ad1201"><td class="memItemLeft" align="right" valign="top">void&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="group__hardware__xip__cache.html#ga2d424f9667df473c64d6414f31ad1201">xip_cache_clean_range</a> (uintptr_t start_offset, uintptr_t size_bytes)</td></tr>
<tr class="memdesc:ga2d424f9667df473c64d6414f31ad1201"><td class="mdescLeft">&#160;</td><td class="mdescRight">Clean a range of offsets within the XIP address space.  <a href="group__hardware__xip__cache.html#ga2d424f9667df473c64d6414f31ad1201">More...</a><br /></td></tr>
<tr class="separator:ga2d424f9667df473c64d6414f31ad1201"><td class="memSeparator" colspan="2">&#160;</td></tr>
<tr class="memitem:gab7c42d3c55382977cd691c6535a6aff9"><td class="memItemLeft" align="right" valign="top">void&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="group__hardware__xip__cache.html#gab7c42d3c55382977cd691c6535a6aff9">xip_cache_pin_range</a> (uintptr_t start_offset, uintptr_t size_bytes)</td></tr>
<tr class="memdesc:gab7c42d3c55382977cd691c6535a6aff9"><td class="mdescLeft">&#160;</td><td class="mdescRight">Pin a range of offsets within the XIP address space.  <a href="group__hardware__xip__cache.html#gab7c42d3c55382977cd691c6535a6aff9">More...</a><br /></td></tr>
<tr class="separator:gab7c42d3c55382977cd691c6535a6aff9"><td class="memSeparator" colspan="2">&#160;</td></tr>
</table>
<a name="details" id="details"></a><h2 class="groupheader">Detailed Description</h2>
<p >Low-level cache maintenance operations for the XIP cache. </p>
<p >These functions apply some maintenance operation to either the entire cache contents, or a range of offsets within the downstream address space. Offsets start from 0 (indicating the first byte of flash), so pointers should have XIP_BASE subtracted before passing into one of these functions.</p>
<p >The only valid cache maintenance operation on RP2040 is "invalidate", which tells the cache to forget everything it knows about some address. This is necessary after a programming operation, because the cache does not automatically know about any serial programming operations performed on the external flash device, and could return stale data. </p>
<p >On RP2350, the three types of operation are:</p>
<ul>
<li>Invalidate: tell the cache to forget everything it knows about some address. The next access to that address will fetch from downstream memory.</li>
<li>Clean: if the addressed cache line contains data not yet written to external memory, then write that data out now, and mark the line as "clean" (i.e. not containing uncommitted write data)</li>
<li>Pin: mark an address as always being resident in the cache. This persists until the line is invalidated, and can be used to allocate part of the cache for cache-as-SRAM use.</li>
</ul>
<p >When using both external flash and external RAM (e.g. PSRAM), a simple way to maintain coherence over flash programming operations is to:</p>
<ol type="1">
<li>Clean the entire cache (e.g. using <a class="el" href="group__hardware__xip__cache.html#gab7db8e534f4d6ff4a5fb7b022c3034a4" title="Clean the cache for the entire XIP address space.">xip_cache_clean_all()</a>)</li>
<li>Erase + program the flash using serial SPI commands</li>
<li>Invalidate ("flush") the entire cache (e.g. using <a class="el" href="group__hardware__xip__cache.html#ga080199b0a555c0f19ff05a298fa97676" title="Invalidate the cache for the entire XIP address space.">xip_cache_invalidate_all()</a>)</li>
</ol>
<p >The invalidate ensures the programming is visible to subsequent reads. The clean ensures that the invalidate does not discard any cached PSRAM write data.</p>
<h2 class="groupheader">Function Documentation</h2>
<a id="gab7db8e534f4d6ff4a5fb7b022c3034a4" name="gab7db8e534f4d6ff4a5fb7b022c3034a4"></a>
<h2 class="memtitle"><span class="permalink"><a href="#gab7db8e534f4d6ff4a5fb7b022c3034a4">&#9670;&nbsp;</a></span>xip_cache_clean_all()</h2>

<div class="memitem">
<div class="memproto">
      <table class="memname">
        <tr>
          <td class="memname">void xip_cache_clean_all </td>
          <td>(</td>
          <td class="paramtype">void&#160;</td>
          <td class="paramname"></td><td>)</td>
          <td></td>
        </tr>
      </table>
</div><div class="memdoc">

<p>Clean the cache for the entire XIP address space. </p>
<p >This causes the cache to write out all pending write data to the downstream memory. For example, when suspending the system with state retained in external PSRAM, this ensures all data has made it out to external PSRAM before powering down.</p>
<p >This function is faster than calling <a class="el" href="group__hardware__xip__cache.html#ga2d424f9667df473c64d6414f31ad1201" title="Clean a range of offsets within the XIP address space.">xip_cache_clean_range()</a> for the entire address space, because it iterates over cachelines instead of addresses.</p>
<p >On RP2040 this is a no-op, as the XIP cache is read-only. This is indicated by the XIP_CACHE_IS_READ_ONLY macro. </p>
<p >On RP2350, due to the workaround applied for RP2350-E11, this function also effectively invalidates all cache lines after cleaning them. The next access to each line will miss. Avoid this by calling <a class="el" href="group__hardware__xip__cache.html#ga2d424f9667df473c64d6414f31ad1201" title="Clean a range of offsets within the XIP address space.">xip_cache_clean_range()</a> which does not suffer this issue.  </p>

</div>
</div>
<a id="ga2d424f9667df473c64d6414f31ad1201" name="ga2d424f9667df473c64d6414f31ad1201"></a>
<h2 class="memtitle"><span class="permalink"><a href="#ga2d424f9667df473c64d6414f31ad1201">&#9670;&nbsp;</a></span>xip_cache_clean_range()</h2>

<div class="memitem">
<div class="memproto">
      <table class="memname">
        <tr>
          <td class="memname">void xip_cache_clean_range </td>
          <td>(</td>
          <td class="paramtype">uintptr_t&#160;</td>
          <td class="paramname"><em>start_offset</em>, </td>
        </tr>
        <tr>
          <td class="paramkey"></td>
          <td></td>
          <td class="paramtype">uintptr_t&#160;</td>
          <td class="paramname"><em>size_bytes</em>&#160;</td>
        </tr>
        <tr>
          <td></td>
          <td>)</td>
          <td></td><td></td>
        </tr>
      </table>
</div><div class="memdoc">

<p>Clean a range of offsets within the XIP address space. </p>
<p >This causes the cache to write out pending write data at these offsets to the downstream memory.</p>
<p >On RP2040 this is a no-op, as the XIP cache is read-only. This is indicated by the XIP_CACHE_IS_READ_ONLY macro. </p>
<dl class="params"><dt>Parameters</dt><dd>
  <table class="params">
    <tr><td class="paramname">start_offset</td><td>The first offset to be invalidated. Offset 0 means the first byte of XIP memory (e.g. flash). Pointers must have XIP_BASE subtracted before passing into this function. Must be aligned to the start of a cache line (XIP_CACHE_LINE_SIZE).</td></tr>
    <tr><td class="paramname">size_bytes</td><td>The number of bytes to clean. Must be a multiple of XIP_CACHE_LINE_SIZE. </td></tr>
  </table>
  </dd>
</dl>

</div>
</div>
<a id="ga080199b0a555c0f19ff05a298fa97676" name="ga080199b0a555c0f19ff05a298fa97676"></a>
<h2 class="memtitle"><span class="permalink"><a href="#ga080199b0a555c0f19ff05a298fa97676">&#9670;&nbsp;</a></span>xip_cache_invalidate_all()</h2>

<div class="memitem">
<div class="memproto">
      <table class="memname">
        <tr>
          <td class="memname">void xip_cache_invalidate_all </td>
          <td>(</td>
          <td class="paramtype">void&#160;</td>
          <td class="paramname"></td><td>)</td>
          <td></td>
        </tr>
      </table>
</div><div class="memdoc">

<p>Invalidate the cache for the entire XIP address space. </p>
<p >Invalidation ensures that subsequent reads will fetch data from the downstream memory, rather than using (potentially stale) cached data.</p>
<p >This function is faster than calling <a class="el" href="group__hardware__xip__cache.html#ga1594edcbd2868564b190f3374d3f49eb" title="Invalidate a range of offsets within the XIP address space.">xip_cache_invalidate_range()</a> for the entire address space, because it iterates over cachelines instead of addresses.</p>
<dl class="section note"><dt>Note</dt><dd>Any pending write data held in the cache is lost: you can force the cache to commit these writes first, by calling <a class="el" href="group__hardware__xip__cache.html#gab7db8e534f4d6ff4a5fb7b022c3034a4" title="Clean the cache for the entire XIP address space.">xip_cache_clean_all()</a></dd>
<dd>
Unlike flash_flush_cache(), this function affects <em>only</em> the cache line state. flash_flush_cache() calls a ROM API which can have other effects on some platforms, like cleaning up the bootrom's QSPI GPIO setup on RP2040. Prefer this function for general cache maintenance use, and prefer flash_flush_cache in sequences of ROM flash API calls. </dd></dl>

</div>
</div>
<a id="ga1594edcbd2868564b190f3374d3f49eb" name="ga1594edcbd2868564b190f3374d3f49eb"></a>
<h2 class="memtitle"><span class="permalink"><a href="#ga1594edcbd2868564b190f3374d3f49eb">&#9670;&nbsp;</a></span>xip_cache_invalidate_range()</h2>

<div class="memitem">
<div class="memproto">
      <table class="memname">
        <tr>
          <td class="memname">void xip_cache_invalidate_range </td>
          <td>(</td>
          <td class="paramtype">uintptr_t&#160;</td>
          <td class="paramname"><em>start_offset</em>, </td>
        </tr>
        <tr>
          <td class="paramkey"></td>
          <td></td>
          <td class="paramtype">uintptr_t&#160;</td>
          <td class="paramname"><em>size_bytes</em>&#160;</td>
        </tr>
        <tr>
          <td></td>
          <td>)</td>
          <td></td><td></td>
        </tr>
      </table>
</div><div class="memdoc">

<p>Invalidate a range of offsets within the XIP address space. </p>
<dl class="params"><dt>Parameters</dt><dd>
  <table class="params">
    <tr><td class="paramname">start_offset</td><td>The first offset to be invalidated. Offset 0 means the first byte of XIP memory (e.g. flash). Pointers must have XIP_BASE subtracted before passing into this function. Must be 4-byte-aligned on RP2040. Must be a aligned to the start of a cache line (XIP_CACHE_LINE_SIZE) on other platforms.</td></tr>
    <tr><td class="paramname">size_bytes</td><td>The number of bytes to invalidate. Must be a multiple of 4 bytes on RP2040. Must be a multiple of XIP_CACHE_LINE_SIZE on other platforms.</td></tr>
  </table>
  </dd>
</dl>
<p>Invalidation ensures that subsequent reads will fetch data from the downstream memory, rather than using (potentially stale) cached data.</p>
<dl class="section note"><dt>Note</dt><dd>Any pending write data held in the cache is lost: you can force the cache to commit these writes first, by calling <a class="el" href="group__hardware__xip__cache.html#ga2d424f9667df473c64d6414f31ad1201" title="Clean a range of offsets within the XIP address space.">xip_cache_clean_range()</a> with the same parameters. Generally this is not necessary because invalidation is used with flash (write-behind via programming), and cleaning is used with PSRAM (writing through the cache). </dd></dl>

</div>
</div>
<a id="gab7c42d3c55382977cd691c6535a6aff9" name="gab7c42d3c55382977cd691c6535a6aff9"></a>
<h2 class="memtitle"><span class="permalink"><a href="#gab7c42d3c55382977cd691c6535a6aff9">&#9670;&nbsp;</a></span>xip_cache_pin_range()</h2>

<div class="memitem">
<div class="memproto">
      <table class="memname">
        <tr>
          <td class="memname">void xip_cache_pin_range </td>
          <td>(</td>
          <td class="paramtype">uintptr_t&#160;</td>
          <td class="paramname"><em>start_offset</em>, </td>
        </tr>
        <tr>
          <td class="paramkey"></td>
          <td></td>
          <td class="paramtype">uintptr_t&#160;</td>
          <td class="paramname"><em>size_bytes</em>&#160;</td>
        </tr>
        <tr>
          <td></td>
          <td>)</td>
          <td></td><td></td>
        </tr>
      </table>
</div><div class="memdoc">

<p>Pin a range of offsets within the XIP address space. </p>
<p >Pinning a line at an address allocates the line exclusively for use at that address. This means that all subsequent accesses to that address will hit the cache, and will not go to downstream memory. This persists until one of two things happens:</p>
<ul>
<li>The line is invalidated, e.g. via <a class="el" href="group__hardware__xip__cache.html#ga080199b0a555c0f19ff05a298fa97676" title="Invalidate the cache for the entire XIP address space.">xip_cache_invalidate_all()</a></li>
<li>The same line is pinned at a different address (note lines are selected by address modulo XIP_CACHE_SIZE)</li>
</ul>
<dl class="params"><dt>Parameters</dt><dd>
  <table class="params">
    <tr><td class="paramname">start_offset</td><td>The first offset to be pinnned. Offset 0 means the first byte of XIP memory (e.g. flash). Pointers must have XIP_BASE subtracted before passing into this function. Must be aligned to the start of a cache line (XIP_CACHE_LINE_SIZE).</td></tr>
    <tr><td class="paramname">size_bytes</td><td>The number of bytes to pin. Must be a multiple of XIP_CACHE_LINE_SIZE. </td></tr>
  </table>
  </dd>
</dl>

</div>
</div>
</div><!-- contents -->
</div><!-- doc-content -->

	<script src="main.js"></script>
</body>
</html>